package com.demo.config.apache.NLP;

import cn.hutool.core.util.StrUtil;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.model.StyleDescription;
import org.apache.poi.hwpf.model.StyleSheet;
import org.apache.poi.hwpf.usermodel.CharacterRun;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apdplat.word.WordSegmenter;
import org.apdplat.word.segmentation.Word;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 注：HWPFDocument对应 word的.doc，不支持.docx、、word分词技术
 */
public class ReadWordWithFormat {

	public static void main(String[] args) throws Exception {
		String filePath = "D:\\file\\doc\\招标文件.doc";
		// 打印文件的文本样式、字体大小、是否加粗、字体样式等---可进行区分
		String s = printWord(filePath);
		// printWord2(filePath);
		printWord3(s);
	}

	// word分词技术--可通过NLP词性对照表区分是人名还是其他
	public static void printWord3(String s) throws IOException {
		List<Word> words = WordSegmenter.segWithStopWords(s);
		System.out.println("word" + words);
	}

	// 按照区间层次打印文件的文本 指定开始中文及结束中文及样式
	public static void printWord2(String filePath) throws IOException {
		InputStream is = new FileInputStream(filePath);
		HWPFDocument doc = new HWPFDocument(is);
		Range r = doc.getRange();// 文档范围
		// 标题
		StringBuilder title = new StringBuilder();
		// 正文
		StringBuilder straight = new StringBuilder();

		// 标题集合
		HashSet<String> titleSets = new HashSet<>();
		// 保存数据的开关
		boolean isTrue = true;
		for (int i = 0; i < r.numParagraphs(); i++) {
			// 获取第 i 个段落
			Paragraph p = r.getParagraph(i);
			// 获取段落样式索引
			int styleIndex = p.getStyleIndex();
			// 获取样式表
			StyleSheet styleSheet = doc.getStyleSheet();
			// 通过样式索引获取样式描述
			StyleDescription style = styleSheet.getStyleDescription(styleIndex);
			// 获取样式名称
			String styleName = style.getName();
			if (StrUtil.isNotBlank(p.text())) {

				if (!styleName.contains("目录") && !p.text().contains("第二章") && p.text().contains("第三章")) {
					isTrue = false;
					break;
				}
				if (isTrue) {
					straight.append(p.text());
				}
			}

		}
		System.out.println("文章正文有：" + checkText(straight.toString()));

		doc.close();
	}

	// 打印文件的文本样式、字体大小、是否加粗、字体样式等---可进行区分
	public static String printWord(String filePath) throws IOException {
		InputStream is = new FileInputStream(filePath);
		// 标题
		StringBuilder title = new StringBuilder();

		// 正文
		StringBuilder straight = new StringBuilder();

		// 标题集合
		HashSet<String> titleSets = new HashSet<>();

		if (filePath.endsWith(".doc")) {
			HWPFDocument doc = new HWPFDocument(is);
			Range r = doc.getRange();// 文档范围
			for (int i = 0; i < r.numParagraphs(); i++) {
				// 获取段落
				// 获取第 i 个段落
				Paragraph p = r.getParagraph(i);
				// 获取段落样式索引
				int styleIndex = p.getStyleIndex();
				// 获取样式表
				StyleSheet styleSheet = doc.getStyleSheet();
				// 通过样式索引获取样式描述
				StyleDescription style = styleSheet.getStyleDescription(styleIndex);
				// 获取样式名称
				String styleName = style.getName();

				if (StrUtil.isNotBlank(styleName) && StrUtil.isNotBlank(p.text())) {
					// 标题集合
					titleSets.add(styleName);
					// 打印各段落的格式
					// System.out.println(i+","+styleIndex+","+styleName);
					if (styleName.equals("标题")) {
						title.append(p.text());
					}
					else if (styleName.equals("正文")) {
						straight.append(p.text());
					}
					// ===========================================================
					CharacterRun characterRun = p.getCharacterRun(0);
					// 字体样式
					String fontName = characterRun.getFontName();
					// 字体大小
					int fontSize = characterRun.getFontSize();
					int color = characterRun.getColor();
					// 是否加粗
					boolean bold = characterRun.isBold();
					System.out.println();
					// ===========================================================

				}

			}
			// System.out.println("文章标题有：" + checkText(title.toString()));
			// System.out.println("文章正文有：" + checkText(straight.toString()));
			// System.out.println("文章标题类型有：" + String.join("、", titleSets));

			// ===========================================================
			// ===========================================================
			Pattern pattern = Pattern.compile("(?:[A-Z][a-z]*[\\s]+){2,}");
			Matcher matcher = pattern.matcher(checkText(straight.toString()));
			while (matcher.find()) {
				String name = matcher.group();
				// System.out.println("Found name: " + name);
			}

			doc.close();
		}
		else if (filePath.endsWith(".docx")) {

			// 创建一个新的XWPFDocument对象，从输入流is中读取内容
			XWPFDocument doc = new XWPFDocument(is);
			// 获取段落迭代器
			Iterator<XWPFParagraph> itPara = doc.getParagraphsIterator();
			// 遍历段落
			while (itPara.hasNext()) {
				// 获取下一个段落
				XWPFParagraph paragraph = itPara.next();
				// 获取段落中的所有运行
				List<XWPFRun> runs = paragraph.getRuns();
				// 获取段落样式
				String styleID = paragraph.getStyleID();
				String style = paragraph.getStyle();

				// 检查样式ID是否与标题或正文样式匹配
				if (StrUtil.isNotBlank(styleID)) {
					if (styleID.equals("Heading1") || styleID.equals("Heading2") || styleID.equals("Heading3")) {
						System.out.println("段落字体格式为标题");
					}
					else if (styleID.equals("Normal") || styleID.equals("BodyText")) {
						System.out.println("段落字体格式为正文");
					}
					else {
						System.out.println("段落字体格式未知");
					}
				}

				// 遍历文本段落
				for (XWPFRun run : runs) {
					// 字体样式
					String fontName = run.getFontName();
					// 字体大小
					int fontSize = run.getFontSize();
					String color = run.getColor();
					// 是否加粗
					boolean bold = run.isBold();
					if (StrUtil.isNotBlank(styleID)) {
						if (styleID.contains("Heading")) {
							title.append(paragraph.getText());
						}
						else if (styleID.contains("Normal") || styleID.contains("BodyText")) {
							straight.append(paragraph.getText());
						}
					}
				}

			}
			System.out.println("文章标题有：" + checkText(title.toString()));
			System.out.println("文章正文有：" + checkText(straight.toString()));
			System.out.println("文章标题类型有：" + String.join("、", titleSets));
		}
		else {
			System.out.println("不是word格式");
		}
		return checkText(straight.toString());
	}

	// 针对特殊字符进行解析，可以打印出来
	static String checkText(String allText) {
		// 获取所有文本
		allText = allText.replaceAll("\\t", " "); // 替换制表符为空格
		allText = allText.replaceAll("\\n", "\n"); // 替换换行符为换行
		allText = allText.replaceAll("\\r", ""); // 替换回车符为空字符
		allText = allText.replaceAll("\\p{Z}", ""); // 替换所有其他不可打印字符为空字符

		return allText;

	}

	// void getFont(String path) throws FileNotFoundException {
	//
	//
	// try (POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(path))) {
	//
	// HWPFDocument doc = new HWPFDocument(fs);
	// Range range = doc.getOverallRange();
	//
	// for (int i = 0; i < range.numParagraphs(); i++) {
	// Paragraph paragraph = range.getParagraph(i);
	// for (TextPiece textPiece : paragraph.getT) {
	//
	// // Get text
	// String text = textPiece.getText();
	//
	// // Get font name
	// String fontName = textPiece.getFont().getName();
	//
	// // Get font style (bold, italic, etc.)
	// int fontStyle = textPiece.getCharacterStyle() & 0x00FF;
	// String fontStyleDesc = getFontStyleDescription(fontStyle);
	//
	// // Get font size in half-points
	// int fontSize = textPiece.getFont().getPointSize() * 2;
	//
	// System.out.println(
	// String.format(
	// "Text: %s, Font Name: %s, Font Style: %s, Font Size: %d",
	// text, fontName, fontStyleDesc, fontSize));
	// }
	// }
	// } catch (IOException e) {
	// throw new RuntimeException(e);
	// }
	// }
	//
	// }

	private static String getFontStyleDescription(int fontStyle) {

		Map<Integer, String> fontStyleMap = new HashMap<>();
		fontStyleMap.put(0, "Normal");
		fontStyleMap.put(1, "Bold");
		fontStyleMap.put(2, "Italic");
		fontStyleMap.put(3, "Bold Italic");
		fontStyleMap.put(4, "Underline");
		fontStyleMap.put(5, "Bold Underline");
		fontStyleMap.put(6, "Italic Underline");
		fontStyleMap.put(7, "Bold Italic Underline");
		fontStyleMap.put(8, "Double Underline");
		fontStyleMap.put(9, "Bold Double Underline");
		fontStyleMap.put(10, "Italic Double Underline");
		fontStyleMap.put(11, "Bold Italic Double Underline");
		fontStyleMap.put(12, "Strikethrough");
		fontStyleMap.put(13, "Bold Strikethrough");
		fontStyleMap.put(14, "Italic Strikethrough");
		fontStyleMap.put(15, "Bold Italic Strikethrough");
		fontStyleMap.put(16, "Shadow");
		fontStyleMap.put(17, "Bold Shadow");
		fontStyleMap.put(18, "Italic Shadow");
		fontStyleMap.put(19, "Bold Italic Shadow");
		fontStyleMap.put(20, "Outline");
		fontStyleMap.put(21, "Bold Outline");
		fontStyleMap.put(22, "Italic Outline");
		fontStyleMap.put(23, "Bold Italic Outline");
		fontStyleMap.put(24, "Emboss");
		fontStyleMap.put(25, "Bold Emboss");
		fontStyleMap.put(26, "Italic Emboss");
		fontStyleMap.put(27, "Bold Italic Emboss");
		fontStyleMap.put(28, "Engrave");
		fontStyleMap.put(29, "Bold Engrave");
		fontStyleMap.put(30, "Italic Engrave");
		fontStyleMap.put(31, "Bold Italic Engrave");

		return fontStyleMap.getOrDefault(fontStyle, "Unknown");

	}

}